#pragma once
#include <iostream>
#include <winsock2.h>  
#include <ws2tcpip.h>  
#include <iostream>  
#include <string>  
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")   

#define DEFAULT_PORT "27015"  
#define DEFAULT_BUFFER_LENGTH 1024  

const SOCKET defaultsockfd = -1;

class TcpClientSocket
{
public:
    TcpClientSocket():_fd(defaultsockfd) 
    {}

    bool Init(const std::string& peerip, uint16_t peerport)
    {
        WSADATA wsaData;
        int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (result != 0) 
        {
            std::cerr << "WSAStartup failed: " << result << std::endl;
            return false;
        }

        //addrinfo hints = {};
        //hints.ai_family = AF_INET;
        //hints.ai_socktype = SOCK_STREAM;
        //hints.ai_protocol = IPPROTO_TCP;

        //result = getaddrinfo(peerip.c_str(), peerport.c_str(), &hints, &_resultList);
        //if (result != 0) 
        //{
        //    std::cerr << "getaddrinfo failed: " << result << std::endl;
        //    WSACleanup();
        //    return false;
        //}

        _fd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_fd == INVALID_SOCKET) 
        {
            std::cerr << "Error at socket(): " << WSAGetLastError() << std::endl;
            WSACleanup();
            return false;
        }

        sockaddr_in serverAddr;
        memset(&serverAddr, 0, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = ::htons(peerport);
        serverAddr.sin_addr.s_addr = ::inet_addr(peerip.c_str());

        result = ::connect(_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
        if (result == SOCKET_ERROR) 
        {
            std::cerr << "connect failed: " << WSAGetLastError() << std::endl;
            closesocket(_fd);
            WSACleanup();
            return false;
        }

        return true;
    }

    bool SetNonBlock()
    {
        u_long nonblocking = 1;
        if (ioctlsocket(_fd, FIONBIO, &nonblocking) != 0) 
        {
            printf("ioctlsocket failed: %d\n", WSAGetLastError());
            ::closesocket(_fd);
            WSACleanup();
            return false;
        }

        return true;
    }

    bool Send(const std::string& msg)
    {
        int n = ::send(_fd, msg.c_str(), msg.size(), 0);
        return n == msg.size();
    }


    bool Recv(std::string* msg)
    {
        char buffer[DEFAULT_BUFFER_LENGTH];
        int n = ::recv(_fd, buffer, DEFAULT_BUFFER_LENGTH - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            *msg += buffer;
            return true;
        }
        else
        {
            //std::cerr << "recv failed: " << WSAGetLastError() << std::endl;
            return false;
        }
    }

    void Destory()
    {
        ::closesocket(_fd);
        WSACleanup();
    }

    ~TcpClientSocket()
    {
    }
private:
    SOCKET _fd;
    addrinfo _resultList;
};

//int main() {
//
//
//
//
//    freeaddrinfo(resultList);
//
//    std::string message;
//    char buffer[DEFAULT_BUFFER_LENGTH];
//    while (true) {
//        std::cout << "Enter message: ";
//        std::getline(std::cin, message);
//        if (message == "exit") break;
//
//        send(connectSocket, message.c_str(), message.size(), 0);
//
//        int bytesReceived = recv(connectSocket, buffer, DEFAULT_BUFFER_LENGTH, 0);
//        if (bytesReceived > 0) {
//            buffer[bytesReceived] = '\0';
//            std::cout << "Echo: " << buffer << std::endl;
//        }
//        else {
//            std::cerr << "recv failed: " << WSAGetLastError() << std::endl;
//            break;
//        }
//    }
//
//    closesocket(connectSocket);
//    WSACleanup();
//    return 0;
//}